/*
 * 原版接口
 */
import * as server from "@minecraft/server";
/*
 * 导出模块
 */
export {
    // 尝试在游戏内创建实例
    SummoningEntityWithData,
    TrySetPermutation,
    TrySpawnParticle,
    TrySpawnEntity,
    TryFillBlocks,
    TrySpawnItem,
    // 获取特定实体队列并执行回调函数
    GetContractRoles,
    EntitysSort,
    GetPartner,
    // 对游戏实例进行翻译
    EntityTranslate,
    BlockTranslate,
    ItemTranslate,
    // 判断实体血量
    HealthHigher,
    HealthBelow,
    // 对容器内的物品进行操作
    DisplaceItemStack,
    DeleteItemStack,
    AlterDurability,
    CheckItemStack,
    SetDurability,
    // 杂项功能
    DistanceAndName,
    PlayerInPower,
    IntelMessage,
    CompileSign,
    ToUnicode
};
/**
 * * 召唤一个带有附加数据的实体
 * 
 * @param {server.Player} player - 执行召唤事件的玩家
 * 
 * @param {server.Container} container - 玩家的背包容器
 * 
 * @param {string} type - 召唤的实体类型
 */
function SummoningEntityWithData(player: server.Player, container: server.Container, type: string) {
    /**
     * * 玩家手持的物品
     */
    const item = container?.getItem(player.selectedSlotIndex);
    /**
     * * 玩家指向的方块
     */
    const block = player.getBlockFromViewDirection({ maxDistance: 16 })?.block;
    /**
     * * 实体动态属性
     */
    const propertyID = item?.getDynamicPropertyIds().filter(type => !type.startsWith('reduction_pureness:'));
    /**
     * * 被记录的实体名称
     */
    const nameTag = item?.getDynamicProperty('reduction_pureness:name') as string;
    /**
     * * 获取 标签组
     */
    const tags = item?.getDynamicProperty('reduction_pureness:tags') as string;
    /**
     * * 物品记录的实体
     */
    const entity = TrySpawnEntity(player.dimension, type, block?.center() ?? player.location);
    // 判断 实体是否存在
    if (entity instanceof Error) return player.sendMessage(`§l§4<§c 召唤失败 §4>§r: ${entity.message}`);
    // 播放 音效
    player.playSound('conduit.deactivate');
    // 绑定玩家
    server.system.run(() => entity.getComponent('tameable')?.tame(player));
    // 消耗物品
    server.system.run(() => container.setItem(player.selectedSlotIndex));
    // 判断 物品 与 属性 是否存在
    if (!item || !propertyID) return;
    // 注入属性
    server.system.runTimeout(() => propertyID.forEach(id => entity.setDynamicProperty(id, item.getDynamicProperty(id))), 20);
    // 判断 实体名称是否存在
    if (!nameTag) return;
    // 注入名称
    server.system.runTimeout(() => entity.nameTag = nameTag, 15);
    // 判断 实体名称是否存在
    if (!tags) return;
    // 添加实体标签
    (JSON.parse(tags) as string[]).forEach(tag => entity.addTag(tag));
};
/**
 * * 尝试设置 方块状态
 * 
 * @param {server.Block} object - 执行 更新事件 的 方块对象
 * 
 * @param {string} type - 进行 赋值 的 方块状态
 * 
 * @param {string | number | boolean} value - 方块状态值
 * 
 * @returns {Error | void} - 赋值失败 返回 错误信息
 */
function TrySetPermutation(object: server.Block, type: string, value: string | number | boolean): Error | void {
    try {
        /**
         * * 赋值 方块状态
         */
        const state = object.permutation.withState(type, value);
        object.setPermutation(state);
    }
    catch (error) { return error as Error; };
};
/**
 * * 尝试生成 粒子效果
 * 
 * @param {string} typeID - 粒子效果的 type_id
 * 
 * @param {server.Dimension} dimension - 生成粒子效果的维度
 * 
 * @param {server.Vector3} location - 生成粒子效果的位置
 * 
 * @param {server.MolangVariableMap} molang - 粒子效果的Molang变量
 * 
 * @returns {Error | void} - 如果出现错误, 则返回错误对象, 否则返回 undefined
 */
function TrySpawnParticle(dimension: server.Dimension, typeID: string, location: server.Vector3, molang?: server.MolangVariableMap): Error | void {
    try {
        dimension.spawnParticle(typeID, location, molang);
    }
    catch (error) {
        return error as Error;
    }
};
/**
 * * 尝试生成 掉落物
 * 
 * @param {string} item - 掉落物的 type_id
 * 
 * @param {server.Dimension} dimension - 生成 掉落物 的维度
 * 
 * @param {server.Vector3} location - 生成 掉落物 的位置
 * 
 * @returns {Error | void} - 如果出现错误, 则返回错误对象, 否则返回 undefined
 */
function TrySpawnItem(dimension: server.Dimension, item: server.ItemStack, location: server.Vector3): Error | server.Entity {
    try {
        return dimension.spawnItem(item, location);
    }
    catch (error) {
        return error as Error;
    }
};
/**
 * * 尝试填充 区域
 * 
 * @param {server.Dimension} dimension - 填充的维度
 * 
 * @param {server.Vector3} begin - 填充的起始位置
 * 
 * @param {server.Vector3} end - 填充的结束位置
 * 
 * @param {string | server.BlockPermutation | server.BlockType} block - 填充的方块
 * 
 * @param {server.BlockFillOptions} options - 填充的选项
 * 
 * @returns {Error | number} - 如果出现错误, 则返回错误对象, 否则返回 填充的方块数量
 */
function TryFillBlocks(dimension: server.Dimension, begin: server.Vector3, end: server.Vector3, block: string | server.BlockPermutation | server.BlockType, options?: server.BlockFillOptions | undefined): Error | server.ListBlockVolume {
    try {
        return dimension.fillBlocks(new server.BlockVolume(begin, end), block, options);
    }
    catch (error) {
        return error as Error;
    }
};
/**
 * * 尝试生成 实体
 * 
 * @param {string} typeID - 实体的 type_id
 * 
 * @param {server.Dimension} dimension - 生成实体的维度
 * 
 * @param {server.Vector3} location - 生成实体的位置
 * 
 * @returns {Error | void} - 如果出现错误, 则返回错误对象, 否则返回 undefined
 */
function TrySpawnEntity(dimension: server.Dimension, typeID: string, location: server.Vector3): Error | server.Entity {
    try {
        return dimension.spawnEntity(typeID, location);
    }
    catch (error) {
        return error as Error;
    }
};
/**
 * * 获取 实体列表
 * 
 * @param {server.Dimension} dimension - 执行程序的维度
 * 
 * @param {server.EntityQueryOptions} options - 查询实体的选项
 * 
 * @param {(entity0: server.Entity, entity1: server.Entity) => number} onSort - 排序函数
 * 
 * @param {(entity: server.Entity) => boolean} onFilter - 过滤函数
 * 
 * @returns {server.Entity[]} - 实体列表
 */
function EntitysSort(dimension: server.Dimension, options?: server.EntityQueryOptions, onSort?: (entity0: server.Entity, entity1: server.Entity) => number, onFilter?: (entity: server.Entity) => void): server.Entity[] {
    /**
     * * 获取 实体列表
     */
    const entitys = onSort ? dimension.getEntities(options).sort(onSort) : dimension.getEntities(options);
    return onFilter ? entitys.filter(onFilter) : entitys;
};
/**
 * * 获取 签订契约的角色 并 执行事件
 * 
 * @param {server.Player} player - 作为主人的玩家
 * 
 * @param {server.EntityQueryOptions} options - 查询选项
 * 
 * @param {(entity: server.Entity) => void} after - 回调函数
 */
function GetContractRoles(player: server.Player, options: server.EntityQueryOptions, after: (entity: server.Entity) => void) {
    /**
     * * 角色查询选项
     */
    const merge: server.EntityQueryOptions = {
        excludeTypes: ["minecraft:item", "minecraft:xp_orb", player.typeId],
        families: ['starry'],
        ...options
    };
    /**
     * * 附近角色 的 列表
     */
    const roles = player.dimension.getEntities(merge).filter(role => role.getComponent('is_tamed'));
    // 筛选 与玩家 的 契约绑定 的 角色
    roles.filter(role => role.getDynamicProperty('entity:contract_user') == player.id);
    // 遍历 角色队列
    roles.forEach(role => after(role));
};
/**
 * * 获取 队友 并 执行事件
 * 
 * @param object - 实体对象
 * 
 * @param after - 回调函数
 */
function GetPartner(object: server.Entity, after: (entity: server.Entity) => void) {
    /**
     * * 角色查询选项
     */
    const roleOptions: server.EntityQueryOptions = {
        location: object.location,
        families: ['starry'],
        maxDistance: 32
    };
    /**
     * * 玩家查询选项
     */
    const playerOptions: server.EntityQueryOptions = {
        location: object.location,
        maxDistance: 32
    };
    /**
     * * 获取实体列表
     */
    const partner = [
        ...object.dimension.getEntities(roleOptions),
        ...object.dimension.getPlayers(playerOptions)
    ];
    /**
     * * 契约者标识符
     */
    const contract = object.getDynamicProperty('entity:contract_user') as string;
    // 为队友提供暴击增益
    partner.forEach(
        entity => {
            if (entity.id != contract && entity.getDynamicProperty('entity:contract_user') != contract) return;
            after(entity);
        }
    )
};
/**
 * * 对 实体标识 进行翻译
 */
function EntityTranslate(object: server.Entity | string): server.RawMessage {
    /**
     * * 对 实体对象 的 名称标签 进行翻译
     */
    const Case = (intel: server.Entity): server.RawMessage => {
        /** 
         * * 获取识别标识
         */
        const proto = intel.typeId.split(':');
        // 如果实体是玩家, 直接返回玩家的名称
        if (intel.typeId == 'minecraft:player') return { text: intel.nameTag };
        // 如果实体有名称, 返回名称
        else if (intel.nameTag.length >= 1) return { text: intel.nameTag };
        // 否则返回实体的翻译键名
        else return { translate: `entity.${(proto[0] == 'minecraft') ? proto[1] : intel.typeId}.name` };
    };
    /**
     * * 对 实体类型 进行翻译
     */
    const TypeID = (intel: string): server.RawMessage => {
        /** 
         * * 获取识别标识
         */
        const proto = intel.split(':');
        // 否则返回实体的翻译键名
        return { translate: `entity.${(proto[0] == 'minecraft') ? proto[1] : intel}.name` };
    };
    // 根据类型进行翻译
    if (typeof object == 'string') return TypeID(object)
    else return Case(object);
};
/**
 * * 对 物品标识 进行翻译
 */
function ItemTranslate(object: server.ItemStack | string): server.RawMessage {
    /**
     * * 对 物品堆栈对象 的 名称标签 进行翻译
     */
    const Case = (intel: server.ItemStack): server.RawMessage => {
        /** 
         * * 获取识别标识
         */
        const proto = intel.typeId.split(':');
        // 构建物品的翻译键名
        return { translate: `item.${(proto[0] == 'minecraft') ? proto[1] : intel.typeId}${(proto[0] == 'minecraft') ? '.name' : ''}` }
    };
    /**
     * * 对 物品类型 进行翻译
     */
    const TypeID = (intel: string): server.RawMessage => {
        /** 
         * * 获取识别标识
         */
        const proto = intel.split(':');
        // 构建物品的翻译键名
        return { translate: `item.${(proto[0] == 'minecraft') ? proto[1] : intel}${(proto[0] == 'minecraft') ? '.name' : ''}` }
    };
    // 根据类型进行翻译
    if (typeof object == 'string') return TypeID(object)
    else return Case(object);
};
/**
 * * 对 方块标识 进行翻译
 */
function BlockTranslate(object: server.Block | string): server.RawMessage {
    /**
     * * 对 方块对象 的 名称标签 进行翻译
     */
    const Case = (intel: server.Block): server.RawMessage => {
        /** 
         * * 获取识别标识
         */
        const proto = intel.typeId.split(':');
        // 构建方块的翻译键名
        return { translate: `tile.${(proto[0] == 'minecraft') ? proto[1] : intel.typeId}.name` }
    };
    /**
     * * 对 方块类型 进行翻译
     */
    const TypeID = (intel: string): server.RawMessage => {
        /** 
         * * 获取识别标识
         */
        const proto = intel.split(':');
        // 构建方块的翻译键名
        return { translate: `tile.${(proto[0] == 'minecraft') ? proto[1] : intel}.name` }
    };
    // 根据类型进行翻译
    if (typeof object == 'string') return TypeID(object)
    else return Case(object);
};
/**
 * * 判断 实体当前生命值 是否低于 指定百分比
 * 
 * @param {server.EntityHealthComponent} health - 实体生命值组件
 * 
 * @param {number} percentage - 百分比
 * 
 * @returns {boolean} - 返回 实体当前生命值 是否低于 指定百分比
 */
function HealthBelow(health: server.EntityHealthComponent, percentage: number): boolean {
    /**
     * * 当前生命值
     */
    const current = health.currentValue;
    /**
     * * 最大生命值
     */
    const maximum = health.defaultValue;
    // 返回测试结果
    return maximum * percentage >= current;
};
/**
 * * 判断 实体当前生命值 是否高于 指定百分比
 * 
 * @param {server.EntityHealthComponent} health - 实体生命值组件
 * 
 * @param {number} percentage - 百分比
 * 
 * @returns {boolean} - 返回 实体当前生命值 是否高于 指定百分比
 */
function HealthHigher(health: server.EntityHealthComponent, percentage: number): boolean {
    /**
     * * 当前生命值
     */
    const current = health.currentValue;
    /**
     * * 最大生命值
     */
    const maximum = health.defaultValue;
    // 返回测试结果
    return maximum * percentage <= current;
};
/**
 * * 删除 容器中 物品对象
 * 
 * @param {server.Container} container - 要进行 检测 的 容器对象
 * 
 * @param {server.ItemStack} sample - 要进行 检测 的 物品对象集
 * 
 * @returns {boolean} - 是否成功
 */
function DeleteItemStack(container: server.Container, sample: server.ItemStack): boolean {
    // 遍历 容器中的 物品对象
    for (let index = 0; index < container.size; index++) {
        /**
         * * 获取 物品对象
         */
        const item = container.getItem(index);
        // 排除 无效的 物品对象
        if (!item || item.typeId !== sample.typeId || item.amount < sample.amount) continue;
        //减少 物品堆栈
        if (item.amount > sample.amount) {
            item.amount -= sample.amount;
            container.setItem(index, item);
        }
        else container.setItem(index);
        // 输出 物品删除成功
        return true;
    };
    // 输出 物品删除失败
    return false;
};
/**
 * * 检测 容器中 物品对象
 * 
 * @param {server.Container} container - 要进行 检测 的 容器对象
 * 
 * @param {server.ItemStack[]} samples - 要进行 检测 的 物品对象集
 * 
 * @returns {boolean} - 是否成功
 */
function CheckItemStack(container: server.Container, samples: server.ItemStack[]): boolean {
    /**
     * * 样本数据集
     */
    const types = new Map<string, number>(samples.map(item => [item.typeId, item.amount]));
    /**
     * * 容器物品数据集
     */
    const items = new Map<string, number>();
    // 遍历 容器内容
    for (let index = 0; index < container.size; index++) {
        const item = container.getItem(index);
        if (!item) continue;
        items.set(item.typeId, item.amount);
    };
    // 判断 容器数据集
    return [...types].every(item => items.has(item[0]) && (items.get(item[0]) ?? 0 >= item[1]));
};
/**
 * * 替换 容器中 物品对象
 * 
 * @param {server.Container} container - 要进行 检测 的 容器对象
 * 
 * @param {server.ItemStack} proto - 需要替换 的 物品对象
 * 
 * @param {server.ItemStack} fresh - 替换后 的 物品对象
 * 
 * @param {boolean} omitAmount - 是否忽略数量
 * 
 * @returns {server.ItemStack[]} - 检测到的 物品对象集
 */
function DisplaceItemStack(container: server.Container, proto: server.ItemStack, fresh: server.ItemStack, omitAmount?: boolean): server.ItemStack[] {
    /**
     * * 物品对象集
     */
    const output: server.ItemStack[] = [];
    // 遍历 容器中的 物品对象
    for (let index = 0; index < container.size; index++) {
        /**
         * * 获取 物品对象
         */
        const item = container.getItem(index);
        // 排除无效的物品对象
        if (!item || item.typeId != proto.typeId) continue;
        if (!omitAmount && proto.amount != item.amount) continue;
        if (proto.getLore.toString() != item.getLore.toString()) continue;
        // 替换 物品对象
        container.setItem(index, fresh);
        // 输出 物品对象
        output.push(item);
    };
    // 返回 物品对象集
    return output;
};
/**
 * * 设置 物品耐久
 * 
 * @param {server.Player} source 发起修改 的 玩家
 * 
 * @param {server.ItemStack} item 进行修改 的 物品
 * 
 * @param {server.Container} container 进行修改 的 物品容器
 * 
 * @param {number} slot 进行修改 的 物品槽位
 * 
 * @param {number} value 物品耐久 的 偏移量
 */
function SetDurability(source: server.Player, item: server.ItemStack, container: server.Container, slot: number, value: number) {
    /**
     * * 获取 物品耐久组件
     */
    const durability = item.getComponent('minecraft:durability');
    // 判断 物品耐久组件 或 容器是否存在
    if (!durability || !container) return;
    // 更新 物品耐久
    if (durability.damage <= durability.maxDurability - value) {
        durability.damage += value;
        container.setItem(slot, item);
    }
    else {
        container.setItem(slot);
        source.playSound('random.anvil_break');
    };
};
/**
 * * 改变 物品耐久
 * 
 * @param {server.ItemStack} item - 物品
 * 
 * @param {number} value - 更新的数值
 * 
 * @returns {server.ItemStack | undefined} - 返回修改后的 物品
 */
function AlterDurability(item: server.ItemStack, value: number): server.ItemStack | undefined {
    /**
     * * 获取 物品耐久组件
     */
    const getDurability = item.getComponent('minecraft:durability');
    // 判断 物品耐久组件 是否存在
    if (!getDurability) return item;
    // 更新 物品耐久
    if (getDurability.damage <= getDurability.maxDurability - value) {
        getDurability.damage += value;
        return item;
    }
    else return undefined;
};
/**
 * * 使用 小标题 的 形式 向 玩家 显示特定信息
 *
 * @param {server.Block | server.Entity | server.Player} object 播报 信息 的 实例对象
 * 
 * @param {number} range 信息 的 广播范围
 * 
 * @param {string} text 信息 的 文本类型
 */
function IntelMessage(object: server.Block | server.Entity | server.Player, range: number, text: string | server.RawMessage) {
    /**
     * * 设置广播范围
     */
    const setOptions: server.EntityQueryOptions = {
        location: object.location,
        maxDistance: range
    };
    /**
     * * 获取玩家队列
     */
    const getPlayers = object.dimension.getPlayers(setOptions);
    //遍历玩家队列 播放文本信息
    getPlayers.forEach(info => info.onScreenDisplay.setActionBar(text));
};
/**
 * * 尝试获取 诸界道标
 * 
 * @param {server.Player} object - 作为 信息源 的 玩家对象
 * 
 * @param {string} input - 获取信息 的 键
 * 
 * @param {Map<string, data_format.LOCATION_AND_DIMENSION>} output - 存储信息 的 数组
 */
function CompileSign(object: server.Player, input: string, output: Map<string, { location: server.Vector3, dimension: server.Dimension }>) {
    /**
     * * 获取 json信息
     */
    const source = JSON.parse(object.getDynamicProperty(input) as string) as { location: server.Vector3, dimension: string }
    /**
     * * 获取 目标维度
     */
    const getDimension = server.world.getDimension(source.dimension);
    output.set(input, { location: source.location, dimension: getDimension });
};
/**
 * * 判断 玩家是否是 创造模式
 * 
 * @param {server.Player} object - 进行查询玩家对象
 * 
 * @returns {boolean} - 返回 玩家是否是 创造模式
 */
function PlayerInPower(object: server.Player): boolean {
    /**
     * * 获取 创造模式的 玩家列表
     */
    const players = object.dimension.getPlayers({ gameMode: server.GameMode.creative });
    /**
     * * 判断玩家是否是创造模式
     */
    const creative = players.filter(player => player.id == object.id).length != 0;
    // 返回测试结果
    return creative;
};
/**
 * * 将JSON字符串中的特定字符转换为Unicode编码的十六进制形式
 * 
 * * 对大写字母, 小写字母, 中文字符进行编码, 同时将特定的 Unicode 编码转换为 true 和 false
 * 
 * @param {string} input - 待处理的 JSON 字符串
 * 
 * @return {string} 处理后的 JSON 字符串
 */
function ToUnicode(input: string): string {
    /**
     * * 将字符串转换为字符数组
     */
    const chars = input.split('');
    /**
     * * 将字符数组转换为 Unicode字符串
     */
    const compile = chars.map(
        char => {
            /**
             * * 获取字符的 Unicode 编码
             */
            const code = char.charCodeAt(0);
            // 对大写字母进行Unicode编码
            if (code >= 0x0041 && code <= 0x005A) return `\\u${code.toString(16).padStart(4, '0')}`;
            // 对小写字母进行Unicode编码
            else if (code >= 0x0061 && code <= 0x007A) return `\\u${code.toString(16).padStart(4, '0')}`;
            // 对中文字符进行Unicode编码
            else if (code >= 0x4E00 && code <= 0x9FA5) return `\\u${code.toString(16).padStart(4, '0')}`;
            // 其他字符保持不变
            else return char;
        }
    ).join('');
    // 将特定的 Unicode 编码转换为 true 和 false
    return compile
        .replace(/\\u0074\\u0072\\u0075\\u0065/g, 'true')
        .replace(/\\u0066\\u0061\\u006c\\u0073\\u0065/g, 'false');
};
/** 
 * * 编写 实体翻译 与 距离信息 文本组件
 * 
 * @param {server.Entity} entity - 实体
 * 
 * @param {number} distance - 距离
 * 
 * @returns {server.RawMessage} - 返回 实体翻译 与 距离信息 文本组件
 */
function DistanceAndName(entity: server.Entity, distance: number): server.RawMessage {
    return {
        rawtext: [
            { text: '§l' }, EntityTranslate(entity), { text: `\n§9距离: §5${distance}` }
        ]
    }
};